#include "./make_ice_task.h"
#include "../../driver/ice/compr.h"
#include "../../driver/ice/sensor.h"
#include "../../driver/ice/stir_motor.h"
#include "../../utils/progress.h"
#include "../../driver/ice/parts.h"
#include "../../driver/ice/sensor.h"
namespace task {

using namespace driver;
using namespace utils;

constexpr uint16_t MIN_STIR_SPEED = 33;
constexpr uint32_t STIR_SPEED_FAIL_DURATION = 60 * 1000;

void MakeIceTask::run() {
    
    for (;;) {
        switch (m_state) {
            case State::IDLE: do_idle(); break;
            case State::STIR_BEGIN: do_stir_begin(); break;
            case State::WORK: do_work(); break;
            case State::STIR_END: do_stir_end(); break;
            case State::INVALID:
            case State::STOP:
            case State::FAIL:
            case State::TIMEOUT: do_stop(); break;
        }
    }
}

bool MakeIceTask::can_start() {
    return (compr->close_duration() + m_stir_compr_delay) >= compr->OPEN_DURATION;
}

void MakeIceTask::do_idle() {

    uint32_t cond_count = 0;

    for (;;) {
        if (sensor->is_bucket_low() && 
           (!sensor->is_ice_full()) &&
           can_start()) 
        {
            cond_count ++;
            if (cond_count >= 5) {
                m_state = State::STIR_BEGIN;
                break;
            }
        } else {
            cond_count = 0;
        }

        if (wait(500)) {
            break;
        }
    }
}

void MakeIceTask::do_stir_begin() {
    stirMotor->open();
    bool ret = wait(m_stir_compr_delay);
    stirMotor->close_once();
    if (ret) {
        return;
    }
    m_state = State::WORK;
}

void MakeIceTask::do_work() {
    uint32_t cond_count = 0;
    Progress prog;
    uint32_t fail_count = 0;

    if (!compr->open()) {
        m_state = State::INVALID;
        return;
    }
    stirMotor->open();
    parts->open_fan();

    for (;;) {
        if (!sensor->is_bucket_low()) {
            m_state = State::IDLE;
            break;
        }

        if (sensor->stir_speed() < MIN_STIR_SPEED) {
            fail_count += 1000;
            if (fail_count >= STIR_SPEED_FAIL_DURATION) {
                m_state = State::FAIL;
                break;
            }
        } else {
            fail_count = 0;
        }

        if (sensor->is_ice_full()) {
            cond_count ++;
            if (cond_count >= 20) {
                m_state = State::STIR_END;
                m_stir_compr_delay = RUN_STIR_COMPR_DELAY;
                break;
            }
        } else {
            cond_count = 0;
        }

        if (prog.is_after(MAKE_ICE_TIMEOUT)) {
            m_state = State::TIMEOUT;
            break;
        }

        if (wait(1000)) {
            break;
        }
    }
    compr->close();
    parts->close_fan();
    stirMotor->close_once();
}

void MakeIceTask::do_stir_end() {
    stirMotor->open();
    bool ret = wait(STOP_STIR_COMPR_DELAY);
    stirMotor->close_once();
    if (ret) {
        return;
    }
    m_state = State::IDLE;
}

void MakeIceTask::do_stop() {
    wait();
}

}
